package com.gxkj.drm.uitls;


import com.gxkj.drm.sdk.annotation.ManagedAttribute;
import com.gxkj.drm.sdk.annotation.ManagedResource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class ScanPackageUtil {

    private static ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    private static MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(
            resourcePatternResolver);

    private static Environment environment = new StandardEnvironment();

    private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";

    public static List<Class<?>> loadMBClasses(String... basePackages) throws IOException, ClassNotFoundException {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        List<Class<?>> clzList = new ArrayList<Class<?>>();

        for (String basePackage : basePackages) {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                    + resolveBasePackage(basePackage) + "/" + DEFAULT_RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);

            for (Resource resource : resources) {
                MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
                AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
                if (annotationMetadata.hasAnnotation(ManagedResource.class.getName())) {
                    ClassMetadata cm = metadataReader.getClassMetadata();
                    Class<?> clz = Class.forName(cm.getClassName());
                    for (Field field : clz.getDeclaredFields()) {
                        if (field.getAnnotation(ManagedAttribute.class) != null) {
                            clzList.add(clz);
                            break;
                        }
                    }
                }
            }
        }

        return clzList;
    }

    private static String resolveBasePackage(String basePackage) {
        return ClassUtils.convertClassNameToResourcePath(environment.resolveRequiredPlaceholders(basePackage));
    }
}
